package com.ayq.activiti.manager.service.impl;

import com.ayq.activiti.common.util.ConstantPool;
import com.ayq.activiti.common.util.DateUtil;
import com.ayq.activiti.manager.domain.applymanager.entity.ActivitiApplyManager;
import com.ayq.activiti.manager.domain.applymanager.repository.ActivitiApplyManagerMapper;
import com.ayq.activiti.manager.domain.examinedistribution.entity.ActivitiExamineDistribution;
import com.ayq.activiti.manager.domain.examinedistribution.repository.ActivitiExamineDistributionMapper;
import com.ayq.activiti.manager.domain.workflow.service.WorkFlowService;
import com.ayq.activiti.manager.dto.WorkFlowOpinionDTO;
import com.ayq.activiti.manager.entity.*;
import com.ayq.activiti.manager.enums.NodeInfoEnum;
import com.ayq.activiti.manager.service.RabbitMqTaskService;
import com.ayq.activiti.manager.util.RedisKit;
import com.ayq.activiti.manager.vo.ActivitiNodeInfoVO;
import com.ayq.activiti.manager.vo.ApprovalecordVO;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.activiti.bpmn.model.*;
import org.activiti.engine.HistoryService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.TaskService;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricDetail;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.history.HistoricVariableUpdate;
import org.activiti.engine.task.Attachment;
import org.activiti.engine.task.Comment;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Service
public class RabbitMqTaskServiceImpl implements RabbitMqTaskService {

    @Autowired
    private RedisKit<Object> redisKit;
    @Autowired
    private ActivitiApplyManagerMapper activitiApplyManagerMapper;
    @Autowired
    private ActivitiExamineDistributionMapper activitiExamineDistributionMapper;
    @Autowired
    private HistoryService historyService;
    @Autowired
    private RepositoryService repositoryService;
    @Autowired
    private WorkFlowService workFlowService;
    @Autowired
    private TaskService taskService;

    /**
     * <p>更新流程节点信息</p>
     * <p>方法名:updateNodeInfo</p>
     *
     * @Author ayq
     * @Date 2021/4/20 11:44
     * @Param [processInstanceId]
     * @Return void
     */
    @Override
    public void updateNodeInfo(String processInstanceId) throws RuntimeException {
        String key = ConstantPool.REDIS_ACTIVITI_HISTORY_GETNODEINFO + processInstanceId;
        //获取历史流程实例
        QueryWrapper<ActivitiApplyManager> wrapper = new QueryWrapper<ActivitiApplyManager>();
        wrapper.eq(ConstantPool.RU_ID, processInstanceId);
        ActivitiApplyManager activitiApplyManager = activitiApplyManagerMapper.selectOne(wrapper);
        if (activitiApplyManager == null) {
            throw new RuntimeException(ConstantPool.CN_SEVENTEEN);
        }
        //获取流程模型
        BpmnModel bpmnModel = repositoryService.getBpmnModel(activitiApplyManager.getProdiId());
        List<HistoricActivityInstance> historicActivityInstances = historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId).list();
        List<FlowInfoEntity> highLightedFlowInfos = new ArrayList<FlowInfoEntity>();
        List<NodeInfoEntity> highLightedNodeInfos = new ArrayList<NodeInfoEntity>();
        Map<String, GraphicInfo> locationMap = bpmnModel.getLocationMap();
        for (HistoricActivityInstance historicActivityInstance : historicActivityInstances) {
            FlowNode mainProcess = (FlowNode) bpmnModel.getMainProcess().getFlowElement(historicActivityInstance.getActivityId(), true);
            List<SequenceFlow> incomingFlows = mainProcess.getIncomingFlows();
            //获取高亮线
            for (SequenceFlow incomingFlow : incomingFlows) {
                FlowElement flowElement = bpmnModel.getFlowElement(incomingFlow.getId());
                if (NodeInfoEnum.getResultEnum(8).getKey().equals(flowElement.getClass().getSimpleName())) {
                    List<Integer> waypoints = incomingFlow.getWaypoints();
                    FlowInfoEntity build = FlowInfoEntity.builder()
                            .startX(String.valueOf(waypoints.get(0)))
                            .startY(String.valueOf(waypoints.get(1)))
                            .endX(String.valueOf(waypoints.get(2)))
                            .endY(String.valueOf(waypoints.get(3)))
                            .build();
                    highLightedFlowInfos.add(build);
                }
            }
            GraphicInfo graphicInfos = locationMap.get(mainProcess.getId());
            String simpleName = mainProcess.getClass().getSimpleName();
            switch (simpleName) {
                case ConstantPool.USER_TASK: {
                    ApprovalecordVO approvalecordVO = workFlowService.getTaskOpinionToTaskId(historicActivityInstance.getTaskId(), activitiApplyManager.getBusinessKey());
                    ApprovalecordEntity approvalecordEntity = ApprovalecordEntity.builder()
                            .approvalUserName(approvalecordVO.getApprovalUserName())
                            .duration(approvalecordVO.getDuration())
                            .endTime(approvalecordVO.getEndTime())
                            .imgPath(approvalecordVO.getImgPath())
                            .opinion(approvalecordVO.getOpinion())
                            .organizationName(approvalecordVO.getOrganizationName())
                            .startTime(approvalecordVO.getStartTime())
                            .taskName(approvalecordVO.getTaskName())
                            .status(approvalecordVO.getStatus())
                            .build();
                    NodeInfoEntity build = NodeInfoEntity.builder()
                            .x(String.valueOf(graphicInfos.getX()))
                            .y(String.valueOf(graphicInfos.getY()))
                            .width(String.valueOf(graphicInfos.getWidth()))
                            .height(String.valueOf(graphicInfos.getHeight()))
                            .taskId(historicActivityInstance.getTaskId())
                            .executId(historicActivityInstance.getExecutionId())
                            .activitiId(historicActivityInstance.getActivityId())
                            .nodeType(NodeInfoEnum.getResultEnum(simpleName).getCode())
                            .approvalecordEntity(approvalecordEntity)
                            .build();
                    highLightedNodeInfos.add(build);
                }
                break;
                case ConstantPool.EXCLUSIVE_GATEWAY: {
                    NodeInfoEntity build = NodeInfoEntity.builder()
                            .x(String.valueOf(graphicInfos.getX()))
                            .y(String.valueOf(graphicInfos.getY()))
                            .width(String.valueOf(graphicInfos.getWidth()))
                            .height(String.valueOf(graphicInfos.getHeight()))
                            .nodeType(NodeInfoEnum.getResultEnum(simpleName).getCode())
                            .build();
                    highLightedNodeInfos.add(build);

                }
                break;
                case ConstantPool.START_EVENT: {
                    ActivitiApplyManagerEntity activitiApplyManagerEntity = ActivitiApplyManagerEntity.builder()
                            .applyUsrName(activitiApplyManager.getApplyUsrName())
                            .businessKey(activitiApplyManager.getBusinessKey())
                            .createTime(activitiApplyManager.getCreateTime())
                            .status(activitiApplyManager.getStatus())
                            .urgency(activitiApplyManager.getUrgency())
                            .variablesJson(activitiApplyManager.getVariablesJson())
                            .workFlowKey(activitiApplyManager.getWorkFlowKey())
                            .build();
                    NodeInfoEntity build = NodeInfoEntity.builder()
                            .x(String.valueOf(graphicInfos.getX()))
                            .y(String.valueOf(graphicInfos.getY()))
                            .width(String.valueOf(graphicInfos.getWidth()))
                            .height(String.valueOf(graphicInfos.getHeight()))
                            .activitiId(historicActivityInstance.getActivityId())
                            .nodeType(NodeInfoEnum.getResultEnum(simpleName).getCode())
                            .activitiApplyManagerEntity(activitiApplyManagerEntity)
                            .build();
                    highLightedNodeInfos.add(build);
                }
                break;
                case ConstantPool.END_EVENT: {
                    NodeInfoEntity build = NodeInfoEntity.builder()
                            .x(String.valueOf(graphicInfos.getX()))
                            .y(String.valueOf(graphicInfos.getY()))
                            .width(String.valueOf(graphicInfos.getWidth()))
                            .height(String.valueOf(graphicInfos.getHeight()))
                            .activitiId(historicActivityInstance.getActivityId())
                            .nodeType(NodeInfoEnum.getResultEnum(simpleName).getCode())
                            .build();
                    highLightedNodeInfos.add(build);
                }
                break;
                //待用
                case ConstantPool.PARALLEL_GATEWAY:
                case ConstantPool.SERVICE_TASK:
                case ConstantPool.MANUAL_TASK: {
                }
                break;
            }
        }
        ActivitiNodeInfoVO build = ActivitiNodeInfoVO.builder()
                .processInstanceId(processInstanceId)
                .businessKey(activitiApplyManager.getBusinessKey())
                .highLightedFlowInfos(highLightedFlowInfos)
                .highLightedNodeInfos(highLightedNodeInfos)
                .status(activitiApplyManager.getStatus())
                .build();
        if (redisKit.hasKey(key)) {
            redisKit.del(key);
        }
        redisKit.set(key, build, DateUtil.getNextDayTime(), TimeUnit.SECONDS);
    }

    /**
     *
     * <p>更新业务历史审核意见</p>
     * <p>方法名:getTaskOpinionList</p>
     * @Author ayq
     * @Date 2021/4/22 15:11
     * @Param [workFlowOpinionDTO]
     * @Return void
     */
    @Override
    public void upodateTaskOpinionList(WorkFlowOpinionDTO workFlowOpinionDTO) throws RuntimeException {
        if (StringUtils.isBlank(workFlowOpinionDTO.getBusinessKey())) {
            throw new RuntimeException(ConstantPool.CN_ONE);
        }
        if (StringUtils.isBlank(workFlowOpinionDTO.getProcessInstanceId())) {
            throw new RuntimeException(ConstantPool.CN_EIGHT);
        }
        String[] split = workFlowOpinionDTO.getBusinessKey().split("\\.");
        if (split.length != 4) {
            throw new RuntimeException(ConstantPool.CN_TWO + workFlowOpinionDTO.getBusinessKey());
        }
        String key = ConstantPool.REDIS_ACTIVITI_HISTORY_GETTASKOPINIONLIST + workFlowOpinionDTO.getProcessInstanceId()  + "." + workFlowOpinionDTO.getBusinessKey();
        List<HistoricTaskInstance> listHis = historyService.createHistoricTaskInstanceQuery()
                .processInstanceBusinessKey(workFlowOpinionDTO.getBusinessKey())
                .processInstanceId(workFlowOpinionDTO.getProcessInstanceId()).list();
        List<ApprovalecordVO> list = new ArrayList<ApprovalecordVO>();
        for (HistoricTaskInstance historicTaskInstance : listHis) {
            StringBuffer userName = new StringBuffer();
            ApprovalecordVO build = this.getApprovalecordVO(split, userName, historicTaskInstance);
            list.add(build);

        }
        if (redisKit.hasKey(key)) {
            redisKit.del(key);
        }
        redisKit.set(key, list, DateUtil.getNextDayTime(), TimeUnit.SECONDS);
    }

    private ApprovalecordVO getApprovalecordVO(String[] split, StringBuffer userName, HistoricTaskInstance historicTaskInstance) {
        QueryWrapper<ActivitiExamineDistribution> wrapper = new QueryWrapper<ActivitiExamineDistribution>();
        wrapper.eq(ConstantPool.COMPANY_ID, split[2]).eq(ConstantPool.SYSTEM_ID, split[0]).eq(ConstantPool.BUSINESS_ID, split[1]).eq(ConstantPool.TASK_KEY, historicTaskInstance.getTaskDefinitionKey());
        ActivitiExamineDistribution activitiExamineDistribution = activitiExamineDistributionMapper.selectOne(wrapper);
        String examineNames = activitiExamineDistribution.getExamineNames();
        String examineIds = activitiExamineDistribution.getExamineIds();
        if (StringUtils.isEmpty(examineNames) || StringUtils.isEmpty(examineIds)) {
            throw new RuntimeException(ConstantPool.CN_SIXTEEN);
        }
        String[] split1 = examineNames.split(",");
        String[] split2 = examineIds.split(",");
        if (StringUtils.isNotEmpty(historicTaskInstance.getAssignee())) {
            for (int i = 0; i < split2.length; i++) {
                if (StringUtils.equals(split2[i],historicTaskInstance.getAssignee())) {
                    userName.append(split1[i]);
                }
            }
        } else {
            for (int i = 0; i < split1.length; i++) {
                userName.append(split1[i]).append(",");
            }
            userName.delete(userName.length() - 1, userName.length());
        }
        ApprovalecordVO build = ApprovalecordVO.builder()
                .approvalUserName(userName.toString())
                .taskName(historicTaskInstance.getName())
                .startTime(historicTaskInstance.getStartTime())
                .endTime(historicTaskInstance.getEndTime())
                .duration(historicTaskInstance.getDurationInMillis())
                .build();
        if (StringUtils.isNotEmpty(historicTaskInstance.getAssignee())) {
            HistoricActivityInstance historicActivityInstance = historyService.createHistoricActivityInstanceQuery().processInstanceId(historicTaskInstance.getProcessInstanceId()).taskAssignee(historicTaskInstance.getAssignee()).singleResult();
            List<HistoricDetail> list = historyService.createHistoricDetailQuery().activityInstanceId(historicActivityInstance.getId()).variableUpdates().list();
            for (HistoricDetail historicDetail : list) {
                if (ConstantPool.STATUS.equals(((HistoricVariableUpdate) historicDetail).getVariableName())) {
                    build.setStatus((int) ((HistoricVariableUpdate) historicDetail).getValue());
                }
            }
        } else {
            build.setStatus(2);
        }
        List<Comment> taskComments = taskService.getTaskComments(historicTaskInstance.getId());
        for (Comment taskComment : taskComments) {
            build.setOpinion(taskComment.getFullMessage());
        }
        List<Attachment> taskAttachments = taskService.getTaskAttachments(historicTaskInstance.getId());
        for (Attachment taskAttachment : taskAttachments) {
            build.setImgPath(taskAttachment.getUrl());
        }
        return build;
    }

}
